#include <gtest/gtest.h>

#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>

#include "elisa/elisa_heap.h"

using namespace std;
using namespace elisa;

typedef boost::shared_ptr<string>	StrPtr;
typedef std::vector<StrPtr>			StrVec;

TEST(Heap, Init)
{
	Heap heap(true);

	ASSERT_TRUE(heap.isEmpty());
	ASSERT_FALSE(heap.isFull());
}

TEST(Heap, Allocate)
{
	Heap heap(true);

	long adr = heap.allocate(1024);
	ASSERT_GE(heap.sizeCurrentBox(), 1024);
	
	adr = heap.allocate(sizeof(int));
	heap.setDomain<int>(adr, 1);
	ASSERT_EQ(1, heap.const_domain<int>(adr));
	ASSERT_EQ(1, *(heap.domain<int>(adr)));

	adr = heap.allocate(sizeof(StrVec));
	StrVec v;
	for (int i = 0; i < 1000; ++i)	
		v.push_back(StrPtr(new string("hoge")));
	heap.setDomain<StrVec>(adr, v);
	ASSERT_EQ((string)"hoge", *(heap.const_domain<StrVec>(adr)[100]));

	long adr2 = heap.allocate(sizeof(int));
	heap.setDomain<int>(adr2, 9999);
	//ASSERT_EQ(1, heap.const_domain<int>(adr));
	ASSERT_EQ(9999, heap.const_domain<int>(adr2));

	adr2 = heap.allocate(sizeof(long));
	heap.setDomain<int>(adr2, 3);
	ASSERT_EQ(3, heap.const_domain<int>(adr2));

	for (int i = 0; i < 100; ++i)	
		ASSERT_EQ((string)"hoge", *(heap.const_domain<StrVec>(adr)[i]));
	v[100] = StrPtr(new string("foobar"));
	ASSERT_EQ((string)"foobar", *(heap.const_domain<StrVec>(adr)[100]));

	ASSERT_EQ((long)1, heap.numBox());
}

TEST(Heap, CopyBox)
{
	Heap heap(true);

	long adr1 = heap.allocate<int>();
	heap.setDomain<int>(adr1, 1);
	long adr2 = heap.allocate<int>();
	heap.setDomain<int>(adr2, 2);

	cout << heap.sizeCurrentBox() << endl;

	long ab1 = heap.copyCurrentBoxToBack();

	heap.setDomain<int>(adr1, 3);
	heap.setDomain<int>(adr1, (long)0, 4);

	long adr3 = heap.allocate<int>();
	heap.setDomain<int>(adr3, 5);

	cout << heap.sizeCurrentBox() << endl;

	ASSERT_EQ(3, *(heap.domain<int>(adr1)));
	ASSERT_EQ(3, *(heap.domain<int>(adr1, ab1)));
	ASSERT_EQ(4, *(heap.domain<int>(adr1, (long)0)));
	ASSERT_EQ(2, *(heap.domain<int>(adr2)));
	ASSERT_EQ(2, *(heap.domain<int>(adr2, (long)0)));
	ASSERT_EQ(5, *(heap.domain<int>(adr3)));

	heap.copyBoxToFront(heap.adrCurrentBox(), heap.sizeCurrentBox());

	cout << heap.numBox() << endl;
}

TEST(Heap, SplitBox)
{
	Heap heap(true);

	long adr1 = heap.allocate(sizeof(int));
	heap.setDomain<int>(adr1, 1);

	long adr2 = heap.allocate(sizeof(int));
	heap.setDomain<int>(adr2, 2);

	heap.splitBox<int>(adr1, 3, 4);

	ASSERT_EQ(4, *(heap.domain<int>(adr1, (long)0)));
	ASSERT_EQ(3, *(heap.domain<int>(adr1, (long)1)));
	ASSERT_EQ(2, *(heap.domain<int>(adr2)));
}
